package com.mzj.saas.jobs.bill.service;

import com.mzj.saas.jobs.bill.entity.*;
import com.mzj.saas.jobs.bill.repository.*;
import com.mzj.saas.jobs.commons.DateUtils;
import com.mzj.saas.jobs.commons.SqlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新的账单生成Service--停用   【当前时间生成当前账单】
 */
@Service
public class NewBillService {
    private static Logger log = LoggerFactory.getLogger(NewBillService.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private HouseRepository houseRepository;
    @Autowired
    private HouseContractRepository houseContractRepository;
    @Autowired
    private HouseExpenseOtherRepository houseExpenseOtherRepository;
    @Autowired
    private RentBillRepository rentBillRepository;
    @Autowired
    private RentBillRelationRepository rentBillRelationRepository;
    @Autowired
    private ExpenseBillRepository expenseBillRepository;
    @Autowired
    private ExpenseBillRelationRepository expenseBillRelationRepository;
    @Autowired
    private HouseMatchUserRepository houseMatchUserRepository;
    @Autowired
    private EstateRentBillRepository estateRentBillRepository;
    @Autowired
    private CommunityHouseUserRepository communityHouseUserRepository;
    @Autowired
    private EstateExpenseBillRepository estateExpenseBillRepository;
    @Autowired
    private HouseWaitPaymentDetailRepository houseWaitPaymentDetailRepository;
    @Autowired
    private EstateExpenseBillDetailRepository estateExpenseBillDetailRepository;

    public String work() throws Exception {

        //公租房账单
        houseRentBill();
        houseOtherBill();

        //物业房产账单
        propertyRentBill();
        propertyOtherBill();

        return "SUCCESS";
    }

    //公租房账单-生成租金账单
    public void houseRentBill() throws Exception{
        try {
            log.info("生成租金账单明细  start");

            //当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            Date currentDate = df.parse(df.format(cal.getTime())); //cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(8) and f.house_nature = 1  " ;


            //查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有租金账单规则数据  end");
                return;
            }

            //收费项目id集合
            List<String> expenseId = new ArrayList<>();
            //公租房id集合
            List<String> hIds = new ArrayList<>();

            for(Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            //查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if(projectList.size() == 0){
                log.info(" 没有收费项目数据  end");
                return;
            }

            //公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            //公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            //合同资料Map
            Map<String, List<HouseContract>> houseContractMap = houseContractRepository.findByHouseIdIn(hIds).stream().collect(Collectors.groupingBy(HouseContract::getHouseId));
            //账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            //houseId_chargeType
            for(String houseIdStr : ruleMap.keySet()){

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                //规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }
                Map<String, Object> rMap = rList.get(0);

                //公租房信息
                List<House> hList = houseMap.get(houseId);
                if (CollectionUtils.isEmpty(hList)) {
                    log.warn("未找到公租房信息 houseId={}", houseId);
                    continue;
                }
                House house = hList.get(0);

                //合同信息
                List<HouseContract> cList = houseContractMap.get(house.getId());
                if (CollectionUtils.isEmpty(cList)) {
                    log.warn("未找到合同信息 houseId={}", houseId);
                    continue;
                }
                HouseContract houseContract = cList.get(0);
                Integer flag = (Integer) rMap.get("flag");
                Integer day = (Integer) rMap.get("day");
                Object dateFlagObj = rMap.get("dateFlag");

                List<RentBill> rentBillList = rentBillRepository.findByHouseIdAndChargeTypeOrderByCreateTimeAsc(houseId,1);  //chargeType 收费项目:1租金 2押金
                RentBill endRentBill = rentBillList.get(0); //第一年账单
                Date endTime = endRentBill.getEndTime();

                //计算合同未生成账单的时间周期，按合同设置方式生成
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endTime);
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                Date startDate = df.parse(df.format(calendar.getTime()));//开始时间 = 第一年账单结束时间 + 1天
                Date endDate = df.parse(df.format(houseContract.getEntTime()));

                //规则生成时间
                String createTime =df.format((Date)rMap.get("createTime"));
                String rid = (String) rMap.get("id");

                //只生成当前时间在时间周期内的账单
                if(currentDate.getTime() >= startDate.getTime() &&  currentDate.getTime() <= endDate.getTime() ){
                    //拆分时间段
                    Integer payType = houseContract.getPayType(); //缴纳方式：1首次年付，后续按月 2首次年付、后续按季 3首次年付，后续按半年 4首次年付，后续按年
                    List<Map<String,String>> dateList = new ArrayList<>();
                    Date tempDate = startDate;
                    BigDecimal month = new BigDecimal(1);
                    switch(payType){
                        case 1:
                            dateList = dateList(tempDate , endDate ,1);
                            month = new BigDecimal(1);
                            break;
                        case 2:
                            dateList = dateList(tempDate , endDate ,3);
                            month = new BigDecimal(3);
                            break;
                        case 3:
                            dateList = dateList(tempDate , endDate ,6);
                            month = new BigDecimal(6);
                            break;
                        case 4:
                            dateList = dateList(tempDate , endDate ,12);
                            month = new BigDecimal(12);
                            break;
                    }

                    String cDate = df.format(currentDate);

                    //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                    Boolean flags = false;
                    if(cDate.equals(createTime)){
                        flags = true;
                    }
                    for (Map<String, String> m : dateList) {
                        String start = m.get("start");
                        String end = m.get("end");

                        //获取截止时间
                        Date startTimes = df.parse(start);
                        if(dateFlagObj != null){
                            Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                            if(dateFlag.equals(2)){
                                startTimes = df.parse(end);
                            }
                        }
                        Date closeTime = null;
                        if (flag.equals(1)) {  // 1前 2后
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, -day);
                            closeTime = c.getTime();
                        } else {
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, day);
                            closeTime = c.getTime();
                        }

                        //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                        if( cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime()) ){
                            //按对应方式生成账单
                            Integer billChargeType = 1;
                            //租金 = 面积 * 单价 * 天数
                            BigDecimal rentUnitAmount = new BigDecimal(houseContract.getRentUnitAmount());

                            //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                            BigDecimal temp = houseContract.getHousingArea().multiply(rentUnitAmount).multiply(month) ;
                            Integer cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());

                            //生成租金账单

                            RentBill rentBill = new RentBill();
                            rentBill.setContractNubmer(house.getContractNumber());
                            rentBill.setHouseId(houseId);
                            rentBill.setChargeType(billChargeType);
                            rentBill.setCommunityId(house.getResidenceCommunityId());
                            rentBill.setBuildingNum(house.getBuildingNum());
                            rentBill.setUnit(house.getUnit());
                            rentBill.setOrgId(house.getOrgId());
                            rentBill.setPaymentStatus(0);
                            rentBill.setRoomNumber(house.getRoomNumber());
                            rentBill.setMatchUserId(houseContract.getMatchUserId());
                            rentBill.setCost(cose);
                            rentBill.setMeasureUnit("元/平方米/月");
                            rentBill.setStartTime(df.parse(start));
                            rentBill.setEndTime(df.parse(end));
                            rentBill.setShouldPayTime(closeTime);
                            rentBill.setCreateTime(currentDate);
                            rentBill.setBillType(1);
                            rentBill.setAuditStatus(0);
                            rentBill.setRuleId(rid);


                            rentBillRepository.save(rentBill);
                            //公租房合同与租金/押金账单关系表
                            RentBillRelation relation = new RentBillRelation();
                            relation.setHouseId(rentBill.getHouseId());
                            relation.setRentBillId(rentBill.getId());
                            relation.setMatchUserId(rentBill.getMatchUserId());
                            relation.setContractNubmer(houseContract.getContractNubmer());
                            rentBillRelationRepository.save(relation);

                        }
                    }

                }else{
                    //当前时间不在时间周期内的账单
                    //整个周期账单小于当前时间
                    if(currentDate.getTime() > startDate.getTime() &&  currentDate.getTime() > endDate.getTime()){
                        //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        String curr = df.format(currentDate);
                        if(curr.equals(createTime)){
                            //拆分时间段
                            Integer payType = houseContract.getPayType(); //缴纳方式：1首次年付，后续按月 2首次年付、后续按季 3首次年付，后续按半年 4首次年付，后续按年
                            List<Map<String,String>> dateList = new ArrayList<>();
                            Date tempDate = startDate;
                            BigDecimal month = new BigDecimal(1);
                            switch(payType){
                                case 1:
                                    dateList = dateList(tempDate , endDate ,1);
                                    month = new BigDecimal(1);
                                    break;
                                case 2:
                                    dateList = dateList(tempDate , endDate ,3);
                                    month = new BigDecimal(3);
                                    break;
                                case 3:
                                    dateList = dateList(tempDate , endDate ,6);
                                    month = new BigDecimal(6);
                                    break;
                                case 4:
                                    dateList = dateList(tempDate , endDate ,12);
                                    month = new BigDecimal(12);
                                    break;
                            }

                            for (Map<String, String> m : dateList) {
                                String start = m.get("start");
                                String end = m.get("end");

                                //获取截止时间
                                Date startTimes = df.parse(start);

                                if(dateFlagObj != null){
                                    Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                    if(dateFlag.equals(2)){
                                        startTimes = df.parse(end);
                                    }
                                }

                                Date closeTime = null;
                                if (flag.equals(1)) {  // 1前 2后
                                    Calendar c = Calendar.getInstance();
                                    c.setTime(startTimes);
                                    c.add(Calendar.DAY_OF_MONTH, -day);
                                    closeTime = c.getTime();
                                } else {
                                    Calendar c = Calendar.getInstance();
                                    c.setTime(startTimes);
                                    c.add(Calendar.DAY_OF_MONTH, day);
                                    closeTime = c.getTime();
                                }

                                //按对应方式生成账单
                                Integer billChargeType = 1;
                                //租金 = 面积 * 单价 * 天数
                                BigDecimal rentUnitAmount = new BigDecimal(houseContract.getRentUnitAmount());

                                //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                BigDecimal temp = houseContract.getHousingArea().multiply(rentUnitAmount).multiply(month) ;
                                Integer cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());

                                //生成租金账单

                                RentBill rentBill = new RentBill();
                                rentBill.setContractNubmer(house.getContractNumber());
                                rentBill.setHouseId(houseId);
                                rentBill.setChargeType(billChargeType);
                                rentBill.setCommunityId(house.getResidenceCommunityId());
                                rentBill.setBuildingNum(house.getBuildingNum());
                                rentBill.setUnit(house.getUnit());
                                rentBill.setOrgId(house.getOrgId());
                                rentBill.setPaymentStatus(0);
                                rentBill.setRoomNumber(house.getRoomNumber());
                                rentBill.setMatchUserId(houseContract.getMatchUserId());
                                rentBill.setCost(cose);
                                rentBill.setMeasureUnit("元/平方米/月");
                                rentBill.setStartTime(df.parse(start));
                                rentBill.setEndTime(df.parse(end));
                                rentBill.setShouldPayTime(closeTime);
                                rentBill.setCreateTime(currentDate);
                                rentBill.setBillType(1);
                                rentBill.setAuditStatus(0);
                                rentBill.setRuleId(rid);

                                rentBillRepository.save(rentBill);
                                //公租房合同与租金/押金账单关系表
                                RentBillRelation relation = new RentBillRelation();
                                relation.setHouseId(rentBill.getHouseId());
                                relation.setRentBillId(rentBill.getId());
                                relation.setMatchUserId(rentBill.getMatchUserId());
                                relation.setContractNubmer(houseContract.getContractNubmer());
                                rentBillRelationRepository.save(relation);

                            }

                        }

                    }


                }

            }

            log.info("生成租金账单明细  end");

        }catch (Exception e) {
            log.error("生成租金账单明细异常  " + e.getMessage(), e);
        }
    }

    //公租房账单-其它费用账单
    public void houseOtherBill()throws Exception{
        try {
            log.info("生成其它费用账单明细  start");

            //当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            Date currentDate = df.parse(df.format(cal.getTime())); //cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(1, 2, 3, 4, 5, 6, 7) and r.type = 1  " ;  // type :1公租房 2非公租房

            //查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有其它费用账单规则数据  end");
                return;
            }

            //收费项目id集合
            List<String> expenseId = new ArrayList<>();
            //公租房id集合
            List<String> hIds = new ArrayList<>();

            for(Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            //查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if(projectList.size() == 0){
                log.info(" 没有收费项目数据  end");
                return;
            }

            //收费项目
            Map<String,List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            //公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            //公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            //账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            //houseId_chargeType
            for(String houseIdStr : ruleMap.keySet()){

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                //规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }
                //可能存在多个周期
                for(Map<String, Object> rMap : rList){
                    //公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Object dateFlagObj = rMap.get("dateFlag");

                    //规则生成时间
                    String createTime =df.format((Date)rMap.get("createTime"));
                    String rid = (String) rMap.get("id");
                    Date startDate =df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    //收费项目
                    List<HouseExpenseOther> otherList =  projectMap.get((String)rMap.get("expenseId"));
                    if(otherList == null){
                        log.warn("找不到收费项目，v={}",(String)rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    //只生成当前时间在时间周期内的账单
                    if(currentDate.getTime() >= startDate.getTime() &&  currentDate.getTime() <= endDate.getTime() ){
                        //拆分时间段
                        List<Map<String,String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        switch(chargeMode){
                            case 1:
                                dateList = dateList(tempDate , endDate ,1);
                                month = new BigDecimal(1);
                                break;
                            case 2:
                                dateList = dateList(tempDate , endDate ,3);
                                month = new BigDecimal(3);
                                break;
                            case 3:
                                dateList = dateList(tempDate , endDate ,6);
                                month = new BigDecimal(6);
                                break;
                            case 4:
                                dateList = dateList(tempDate , endDate ,12);
                                month = new BigDecimal(12);
                                break;
                        }

                        String cDate = df.format(currentDate);

                        //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if(cDate.equals(createTime)){
                            flags = true;
                        }
                        for(Map<String, String> m : dateList){
                            String start = m.get("start");
                            String end = m.get("end");
                            //获取截止时间
                            Date startTimes = df.parse(start);

                            if(dateFlagObj != null){
                                Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                if(dateFlag.equals(2)){
                                    startTimes = df.parse(end);
                                }
                            }

                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                closeTime = c.getTime();
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                closeTime = c.getTime();
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if( cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime()) ){
                                //按对应方式生成账单

                                //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                //价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                //计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        //物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        //宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        //电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        //暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                List<String> hlist = new ArrayList<>();
                                hlist.add(houseId);
                                List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist,1);
                                String matchUserId = null;
                                if(hmUserList.size() > 0){
                                    matchUserId = hmUserList.get(0).getMatchUserId();
                                }

                                //生成账单
                                ExpenseBill expenseBill = new ExpenseBill();

                                expenseBill.setHouseId(houseId);
                                expenseBill.setChargeType(chargeType);
                                expenseBill.setCommunityId(house.getResidenceCommunityId());
                                expenseBill.setBuildingNum(house.getBuildingNum());
                                expenseBill.setUnit(house.getUnit());
                                expenseBill.setOrgId(house.getOrgId());
                                expenseBill.setPaymentStatus(0);
                                expenseBill.setRoomNumber(house.getRoomNumber());
                                expenseBill.setMatchUserId(matchUserId);
                                expenseBill.setCost(cose);
                                expenseBill.setMeasureUnit(unit);
                                expenseBill.setStartTime(df.parse(start));
                                expenseBill.setEndTime(df.parse(end));
                                expenseBill.setShouldPayTime(closeTime);
                                expenseBill.setCreateTime(currentDate);
                                expenseBill.setAuditStatus(0);     //审核状态：0未审核 1已审核
                                expenseBill.setBillType(1);
                                expenseBill.setRuleId(rid);

                                ExpenseBill save = expenseBillRepository.save(expenseBill);

                                //公租房合同与其它费用账单关系表 saas_expense_bill_relation
                                ExpenseBillRelation relation = new ExpenseBillRelation();
                                relation.setHouseId(expenseBill.getHouseId());
                                relation.setExpenseBillId(expenseBill.getId());
                                relation.setMatchUserId(expenseBill.getMatchUserId());
                                //relation.setContractNubmer(houseContract.getContractNubmer());

                                expenseBillRelationRepository.save(relation);

                                HouseWaitPaymentDetail houseWaitPaymentDetail = new HouseWaitPaymentDetail();
                                houseWaitPaymentDetail.setExpenseBillId(save.getId());
                                houseWaitPaymentDetail.setChargeType(save.getChargeType());
                                switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 1:
                                        houseWaitPaymentDetail.setWaterStartNum(0);
                                        houseWaitPaymentDetail.setWaterEndNum(0);
                                        houseWaitPaymentDetail.setWaterUsage(0.0);
                                        houseWaitPaymentDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                        break;
                                    case 2:
                                        houseWaitPaymentDetail.setElectricStartNum(0);
                                        houseWaitPaymentDetail.setElectricEndNum(0);
                                        houseWaitPaymentDetail.setElectricUsage(0.0);
                                        houseWaitPaymentDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 3:
                                        houseWaitPaymentDetail.setPropertyFee(save.getCost());
                                        break;
                                    case 4:
                                        houseWaitPaymentDetail.setBroadBandCharges(save.getCost());
                                        break;
                                    case 5:
                                        houseWaitPaymentDetail.setTvFee(save.getCost());
                                        break;
                                    case 6:
                                        houseWaitPaymentDetail.setGasStartNum(0);
                                        houseWaitPaymentDetail.setGasEndNum(0);
                                        houseWaitPaymentDetail.setGasUsage(0.0);
                                        houseWaitPaymentDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 7:
                                        houseWaitPaymentDetail.setHeatingBill(save.getCost());
                                        break;
                                }

                                houseWaitPaymentDetailRepository.save(houseWaitPaymentDetail);

                            }
                        }

                    }else{
                        //当前时间不在时间周期内的账单
                        //整个周期账单小于当前时间
                        if(currentDate.getTime() > startDate.getTime() &&  currentDate.getTime() > endDate.getTime()){
                            //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if(curr.equals(createTime)){
                                //拆分时间段
                                List<Map<String,String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                switch(chargeMode){
                                    case 1:
                                        dateList = dateList(tempDate , endDate ,1);
                                        month = new BigDecimal(1);
                                        break;
                                    case 2:
                                        dateList = dateList(tempDate , endDate ,3);
                                        month = new BigDecimal(3);
                                        break;
                                    case 3:
                                        dateList = dateList(tempDate , endDate ,6);
                                        month = new BigDecimal(6);
                                        break;
                                    case 4:
                                        dateList = dateList(tempDate , endDate ,12);
                                        month = new BigDecimal(12);
                                        break;
                                }

                                for (Map<String, String> m : dateList) {
                                    //按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    //获取截止时间
                                    Date startTimes = df.parse(start);

                                    if(dateFlagObj != null){
                                        Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                        if(dateFlag.equals(2)){
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        closeTime = c.getTime();
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        closeTime = c.getTime();
                                    }


                                    //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    //价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    //计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            //物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            //宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            //电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            //暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    List<String> hlist = new ArrayList<>();
                                    hlist.add(houseId);
                                    List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist,1);
                                    String matchUserId = null;
                                    if(hmUserList.size() > 0){
                                        matchUserId = hmUserList.get(0).getMatchUserId();
                                    }

                                    //生成账单
                                    ExpenseBill expenseBill = new ExpenseBill();

                                    expenseBill.setHouseId(houseId);
                                    expenseBill.setChargeType(chargeType);
                                    expenseBill.setCommunityId(house.getResidenceCommunityId());
                                    expenseBill.setBuildingNum(house.getBuildingNum());
                                    expenseBill.setUnit(house.getUnit());
                                    expenseBill.setOrgId(house.getOrgId());
                                    expenseBill.setPaymentStatus(0);
                                    expenseBill.setRoomNumber(house.getRoomNumber());
                                    expenseBill.setMatchUserId(matchUserId);
                                    expenseBill.setCost(cose);
                                    expenseBill.setMeasureUnit(unit);
                                    expenseBill.setStartTime(df.parse(start));
                                    expenseBill.setEndTime(df.parse(end));
                                    expenseBill.setShouldPayTime(closeTime);
                                    expenseBill.setCreateTime(currentDate);
                                    expenseBill.setAuditStatus(0);     //审核状态：0未审核 1已审核
                                    expenseBill.setBillType(1);
                                    expenseBill.setRuleId(rid);

                                    ExpenseBill save = expenseBillRepository.save(expenseBill);

                                    //公租房合同与其它费用账单关系表 saas_expense_bill_relation
                                    ExpenseBillRelation relation = new ExpenseBillRelation();
                                    relation.setHouseId(expenseBill.getHouseId());
                                    relation.setExpenseBillId(expenseBill.getId());
                                    relation.setMatchUserId(expenseBill.getMatchUserId());
                                    //relation.setContractNubmer(houseContract.getContractNubmer());

                                    expenseBillRelationRepository.save(relation);

                                    HouseWaitPaymentDetail houseWaitPaymentDetail = new HouseWaitPaymentDetail();
                                    houseWaitPaymentDetail.setExpenseBillId(save.getId());
                                    houseWaitPaymentDetail.setChargeType(save.getChargeType());
                                    switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 1:
                                            houseWaitPaymentDetail.setWaterStartNum(0);
                                            houseWaitPaymentDetail.setWaterEndNum(0);
                                            houseWaitPaymentDetail.setWaterUsage(0.0);
                                            houseWaitPaymentDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                            break;
                                        case 2:
                                            houseWaitPaymentDetail.setElectricStartNum(0);
                                            houseWaitPaymentDetail.setElectricEndNum(0);
                                            houseWaitPaymentDetail.setElectricUsage(0.0);
                                            houseWaitPaymentDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 3:
                                            houseWaitPaymentDetail.setPropertyFee(save.getCost());
                                            break;
                                        case 4:
                                            houseWaitPaymentDetail.setBroadBandCharges(save.getCost());
                                            break;
                                        case 5:
                                            houseWaitPaymentDetail.setTvFee(save.getCost());
                                            break;
                                        case 6:
                                            houseWaitPaymentDetail.setGasStartNum(0);
                                            houseWaitPaymentDetail.setGasEndNum(0);
                                            houseWaitPaymentDetail.setGasUsage(0.0);
                                            houseWaitPaymentDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 7:
                                            houseWaitPaymentDetail.setHeatingBill(save.getCost());
                                            break;
                                    }

                                    houseWaitPaymentDetailRepository.save(houseWaitPaymentDetail);

                                }

                            }

                        }

                    }

                }

            }

            log.info("生成其它费用账单明细   end");

        }catch (Exception e){
            log.error("生成其它费用账单明细异常  " + e.getMessage(), e);
        }
    }

    //物业房产账单-生成租金/押金账单
    public void propertyRentBill()throws Exception{
        try {
            log.info(" 生成租金/押金账单明细  start");

            //当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            Date currentDate = df.parse(df.format(cal.getTime())); //cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id,r.date_flag AS dateFlag   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(8,9) and f.house_nature != 1  " ;

            //查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有租金/押金账单规则数据  end");
                return;
            }

            //收费项目id集合
            List<String> expenseId = new ArrayList<>();
            //公租房id集合
            List<String> hIds = new ArrayList<>();

            for(Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            //查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if(projectList.size() == 0){
                log.info(" 没有收费项目数据  end");
                return;
            }

            //收费项目
            Map<String,List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            //公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            //公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            //账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            //houseId_chargeType
            for(String houseIdStr : ruleMap.keySet()){

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                //规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }

                //可能存在多个周期
                for(Map<String, Object> rMap : rList){
                    //公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Object dateFlagObj = rMap.get("dateFlag");

                    //规则生成时间
                    String createTime =df.format((Date)rMap.get("createTime"));
                    String rid = (String) rMap.get("id");
                    Date startDate =df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    //收费项目
                    List<HouseExpenseOther> otherList =  projectMap.get((String)rMap.get("expenseId"));
                    if(otherList == null){
                        log.warn("找不到收费项目，v={}",(String)rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    //只生成当前时间在时间周期内的账单
                    if(currentDate.getTime() >= startDate.getTime() &&  currentDate.getTime() <= endDate.getTime() ){
                        //拆分时间段
                        List<Map<String,String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        switch(chargeMode){
                            case 1:
                                dateList = dateList(tempDate , endDate ,1);
                                month = new BigDecimal(1);
                                break;
                            case 2:
                                dateList = dateList(tempDate , endDate ,3);
                                month = new BigDecimal(3);
                                break;
                            case 3:
                                dateList = dateList(tempDate , endDate ,6);
                                month = new BigDecimal(6);
                                break;
                            case 4:
                                dateList = dateList(tempDate , endDate ,12);
                                month = new BigDecimal(12);
                                break;
                        }

                        String cDate = df.format(currentDate);

                        //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if(cDate.equals(createTime)){
                            flags = true;
                        }

                        for(Map<String, String> m : dateList){
                            String start = m.get("start");
                            String end = m.get("end");

                            //获取截止时间
                            Date startTimes = df.parse(start);

                            if(dateFlagObj != null){
                                Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                if(dateFlag.equals(2)){
                                    startTimes = df.parse(end);
                                }
                            }

                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                closeTime = c.getTime();
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                closeTime = c.getTime();
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if( cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime()) ){
                                //按对应方式生成账单

                                //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                //价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                //计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        //物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        //宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        //电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        //暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 8:
                                        //租金 = 面积 * 单价 * 天数
                                        BigDecimal area2 = house.getArea();
                                        temp = area2.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 9:
                                        //押金 = 单价(一次性)
                                        temp = price;
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                String matchUserId = null;
                                if (communityHouseUserList.size() > 0) {
                                    matchUserId = communityHouseUserList.get(0).getUserId();
                                }

                                //收费项目:8租金 9押金
                                Integer billChargeType = 2;
                                if (chargeType == 8) {
                                    billChargeType = 1;
                                }

                                //生成账单
                                EstateRentBill estateRentBill = new EstateRentBill();
                                estateRentBill.setHouseId(houseId);
                                estateRentBill.setChargeType(billChargeType);
                                estateRentBill.setCommunityId(house.getResidenceCommunityId());
                                estateRentBill.setBuildingNum(house.getBuildingNum());
                                estateRentBill.setUnit(house.getUnit());
                                estateRentBill.setOrgId(house.getHousePropertyId());
                                estateRentBill.setPaymentStatus(0);
                                estateRentBill.setRoomNumber(house.getRoomNumber());
                                estateRentBill.setMatchUserId(matchUserId);
                                estateRentBill.setCost(cose);
                                estateRentBill.setMeasureUnit(unit);
                                estateRentBill.setStartTime(df.parse(start));
                                estateRentBill.setEndTime(df.parse(end));
                                estateRentBill.setShouldPayTime(closeTime);
                                estateRentBill.setCreateTime(currentDate);
                                estateRentBill.setBillType(1);
                                estateRentBill.setAuditStatus(0);     //审核状态：0未审核 1已审核
                                estateRentBill.setRuleId(rid);
                                estateRentBillRepository.save(estateRentBill);

                            }
                        }

                    }else{
                        //当前时间不在时间周期内的账单
                        //整个周期账单小于当前时间
                        if(currentDate.getTime() > startDate.getTime() &&  currentDate.getTime() > endDate.getTime()){
                            //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if(curr.equals(createTime)){
                                //拆分时间段
                                List<Map<String,String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                switch(chargeMode){
                                    case 1:
                                        dateList = dateList(tempDate , endDate ,1);
                                        month = new BigDecimal(1);
                                        break;
                                    case 2:
                                        dateList = dateList(tempDate , endDate ,3);
                                        month = new BigDecimal(3);
                                        break;
                                    case 3:
                                        dateList = dateList(tempDate , endDate ,6);
                                        month = new BigDecimal(6);
                                        break;
                                    case 4:
                                        dateList = dateList(tempDate , endDate ,12);
                                        month = new BigDecimal(12);
                                        break;
                                }

                                for (Map<String, String> m : dateList) {
                                    //按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    //获取截止时间
                                    Date startTimes = df.parse(start);

                                    if(dateFlagObj != null){
                                        Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                        if(dateFlag.equals(2)){
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        closeTime = c.getTime();
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        closeTime = c.getTime();
                                    }


                                    //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    //价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    //计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            //物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            //宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            //电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            //暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 8:
                                            //租金 = 面积 * 单价 * 天数
                                            BigDecimal area2 = house.getArea();
                                            temp = area2.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 9:
                                            //押金 = 单价(一次性)
                                            temp = price;
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                    String matchUserId = null;
                                    if (communityHouseUserList.size() > 0) {
                                        matchUserId = communityHouseUserList.get(0).getUserId();
                                    }

                                    //收费项目:8租金 9押金
                                    Integer billChargeType = 2;
                                    if (chargeType == 8) {
                                        billChargeType = 1;
                                    }

                                    //生成账单
                                    EstateRentBill estateRentBill = new EstateRentBill();
                                    estateRentBill.setHouseId(houseId);
                                    estateRentBill.setChargeType(billChargeType);
                                    estateRentBill.setCommunityId(house.getResidenceCommunityId());
                                    estateRentBill.setBuildingNum(house.getBuildingNum());
                                    estateRentBill.setUnit(house.getUnit());
                                    estateRentBill.setOrgId(house.getHousePropertyId());
                                    estateRentBill.setPaymentStatus(0);
                                    estateRentBill.setRoomNumber(house.getRoomNumber());
                                    estateRentBill.setMatchUserId(matchUserId);
                                    estateRentBill.setCost(cose);
                                    estateRentBill.setMeasureUnit(unit);
                                    estateRentBill.setStartTime(df.parse(start));
                                    estateRentBill.setEndTime(df.parse(end));
                                    estateRentBill.setShouldPayTime(closeTime);
                                    estateRentBill.setCreateTime(currentDate);
                                    estateRentBill.setBillType(1);
                                    estateRentBill.setAuditStatus(0);     //审核状态：0未审核 1已审核
                                    estateRentBill.setRuleId(rid);
                                    estateRentBillRepository.save(estateRentBill);

                                }

                            }

                        }

                    }

                }

            }

            log.info(" 生成租金/押金账单明细  end");

        }catch (Exception e){
            log.error("生成租金/押金账单明细异常  " + e.getMessage(), e);
        }
    }

    //物业房产账单-其它费用账单
    public void propertyOtherBill()throws Exception{
        try{
            log.info(" 生成其它费用账单明细  start");

            //当前时间 [凌晨2点跑前一天的数据]
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Calendar cal = Calendar.getInstance();
            cal.setTime(new Date());
            cal.add(Calendar.DAY_OF_MONTH, -1);
            Date currentDate = df.parse(df.format(cal.getTime())); //cal.getTime()

            String ruleSql = "select f.house_id as houseId, r.charge_type as chargeType,r.start_time AS startTime,r.end_time AS endTime,r.close_time AS closeTime,"
                    + " r.expense_id AS expenseId,r.flag ,r.day ,r.create_time AS createTime ,r.id , f.house_nature AS houseNature,r.date_flag AS dateFlag   "
                    + " from saas_house_expense_rule_ref f left join saas_house_expense_bill_rule r "
                    + "on f.rule_id = r.id where r.charge_type in(1, 2, 3, 4, 5, 6, 7) and r.type = 2  " ; // type :1公租房 2非公租房[包含公租房]

            //查询账单生成规则数据
            List<Map<String, Object>> ruleList = jdbcTemplate.queryForList(ruleSql);
            if (CollectionUtils.isEmpty(ruleList)) {
                log.info(" 没有其它费用账单规则数据  end");
                return;
            }

            //收费项目id集合
            List<String> expenseId = new ArrayList<>();
            //公租房id集合
            List<String> hIds = new ArrayList<>();

            for(Map<String, Object> k : ruleList) {
                hIds.add(k.get("houseId").toString());
                expenseId.add(k.get("expenseId").toString());
            }

            hIds = hIds.stream().distinct().collect(Collectors.toList());

            //查询收费项目
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByIdIn(expenseId);
            if(projectList.size() == 0){
                log.info(" 没有收费项目数据  end");
                return;
            }

            //收费项目
            Map<String,List<HouseExpenseOther>> projectMap = projectList.stream().collect(Collectors.groupingBy(HouseExpenseOther::getId));
            //公租房信息
            List<House> houseList = houseRepository.findByIdIn(hIds);
            //公租房信息Map
            Map<String, List<House>> houseMap = houseList.stream().collect(Collectors.groupingBy(House::getId));
            //账单生成规则信息
            Map<String, List<Map<String, Object>>> ruleMap = ruleList.stream().collect(Collectors.groupingBy((Map<String, Object> m) -> m.get("houseId") + "_" + m.get("chargeType")));

            //houseId_chargeType
            for(String houseIdStr : ruleMap.keySet()){

                String hct[] = houseIdStr.split("_");
                String houseId = hct[0];
                Integer chargeType = Integer.parseInt(hct[1]);

                //规则信息
                List<Map<String, Object>> rList = ruleMap.get(houseIdStr);
                if (CollectionUtils.isEmpty(rList)) {
                    log.warn("未找到规则信息  houseId={}", houseIdStr);
                    continue;
                }

                //可能存在多个周期
                for(Map<String, Object> rMap : rList){
                    //公租房信息
                    List<House> hList = houseMap.get(houseId);
                    if (CollectionUtils.isEmpty(hList)) {
                        log.warn("未找到公租房信息 houseId={}", houseId);
                        continue;
                    }
                    House house = hList.get(0);
                    Integer flag = (Integer) rMap.get("flag");
                    Integer day = (Integer) rMap.get("day");
                    Integer houseNature = (Integer) rMap.get("houseNature");
                    Object dateFlagObj = rMap.get("dateFlag");

                    //规则生成时间
                    String createTime =df.format((Date)rMap.get("createTime"));
                    String rid = (String) rMap.get("id");
                    Date startDate =df.parse(df.format((Date) rMap.get("startTime")));
                    Date endDate = df.parse(df.format((Date) rMap.get("endTime")));
                    //收费项目
                    List<HouseExpenseOther> otherList =  projectMap.get((String)rMap.get("expenseId"));
                    if(otherList == null){
                        log.warn("找不到收费项目，v={}",(String)rMap.get("expenseId"));
                        continue;
                    }
                    HouseExpenseOther other = otherList.get(0);
                    Integer chargeMode = other.getChargeMode();

                    //只生成当前时间在时间周期内的账单
                    if(currentDate.getTime() >= startDate.getTime() &&  currentDate.getTime() <= endDate.getTime() ){
                        //拆分时间段
                        List<Map<String,String>> dateList = new ArrayList<>();
                        Date tempDate = startDate;
                        BigDecimal month = new BigDecimal(1);
                        switch(chargeMode){
                            case 1:
                                dateList = dateList(tempDate , endDate ,1);
                                month = new BigDecimal(1);
                                break;
                            case 2:
                                dateList = dateList(tempDate , endDate ,3);
                                month = new BigDecimal(3);
                                break;
                            case 3:
                                dateList = dateList(tempDate , endDate ,6);
                                month = new BigDecimal(6);
                                break;
                            case 4:
                                dateList = dateList(tempDate , endDate ,12);
                                month = new BigDecimal(12);
                                break;
                        }

                        String cDate = df.format(currentDate);

                        //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                        Boolean flags = false;
                        if(cDate.equals(createTime)){
                            flags = true;
                        }

                        for(Map<String, String> m : dateList){
                            String start = m.get("start");
                            String end = m.get("end");

                            //获取截止时间
                            Date startTimes = df.parse(start);

                            if(dateFlagObj != null){
                                Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                if(dateFlag.equals(2)){
                                    startTimes = df.parse(end);
                                }
                            }

                            Date closeTime = null;
                            if (flag.equals(1)) {  // 1前 2后
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, -day);
                                closeTime = c.getTime();
                            } else {
                                Calendar c = Calendar.getInstance();
                                c.setTime(startTimes);
                                c.add(Calendar.DAY_OF_MONTH, day);
                                closeTime = c.getTime();
                            }

                            //(当前时间 == 开始时间) 或者 (规则生成时间 == 当前时间和开始时间 < 当前时间)
                            if( cDate.equals(start) || (flags && df.parse(start).getTime() < currentDate.getTime()) ){
                                //按对应方式生成账单

                                //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                //价格:单位分
                                Integer cose = 0;
                                BigDecimal price = new BigDecimal(other.getPrice());
                                //计量单位，如：月/度/平方
                                String unit = other.getUnit();
                                BigDecimal temp = null;
                                switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 3:
                                        //物业费 = 面积 * 单价 * 天数
                                        BigDecimal area = house.getArea();
                                        temp = area.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 4:
                                        //宽带费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 5:
                                        //电视费 = 月份 * 单价
                                        temp = month.multiply(price);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                    case 7:
                                        //暖气费 = 面积 * 单价 * 日期
                                        BigDecimal area1 = house.getArea();
                                        temp = area1.multiply(price).multiply(month);
                                        cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                        break;
                                }

                                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                String matchUserId = null;
                                if (communityHouseUserList.size() > 0) {
                                    matchUserId = communityHouseUserList.get(0).getUserId();
                                }

                                if(houseNature != null && houseNature.equals(1)){  // 公租房
                                    List<String> hlist = new ArrayList<>();
                                    hlist.add(houseId);
                                    List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist,1);
                                    if(hmUserList.size() > 0){
                                        matchUserId = hmUserList.get(0).getMatchUserId();
                                    }
                                }

                                //生成账单
                                EstateExpenseBill estateExpenseBill = new EstateExpenseBill();

                                estateExpenseBill.setHouseId(houseId);
                                estateExpenseBill.setChargeType(chargeType);
                                estateExpenseBill.setCommunityId(house.getResidenceCommunityId());
                                estateExpenseBill.setBuildingNum(house.getBuildingNum());
                                estateExpenseBill.setUnit(house.getUnit());
                                estateExpenseBill.setOrgId(house.getHousePropertyId());
                                estateExpenseBill.setPaymentStatus(0);
                                estateExpenseBill.setRoomNumber(house.getRoomNumber());
                                estateExpenseBill.setMatchUserId(matchUserId);
                                estateExpenseBill.setCost(cose);
                                estateExpenseBill.setMeasureUnit(unit);
                                estateExpenseBill.setStartTime(df.parse(start));
                                estateExpenseBill.setEndTime(df.parse(end));
                                estateExpenseBill.setCreateTime(currentDate);
                                estateExpenseBill.setAuditStatus(0);      //'审核状态：0未审核 1已审核'
                                estateExpenseBill.setBillType(1);
                                estateExpenseBill.setShouldPayTime(closeTime);
                                estateExpenseBill.setRuleId(rid);

                                EstateExpenseBill save = estateExpenseBillRepository.save(estateExpenseBill);

                                EstateExpenseBillDetail estateExpenseBillDetail = new EstateExpenseBillDetail();
                                estateExpenseBillDetail.setExpenseBillId(save.getId());
                                estateExpenseBillDetail.setChargeType(save.getChargeType());
                                switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 1:
                                        estateExpenseBillDetail.setWaterStartNum(0);
                                        estateExpenseBillDetail.setWaterEndNum(0);
                                        estateExpenseBillDetail.setWaterUsage(0.0);
                                        estateExpenseBillDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                        break;
                                    case 2:
                                        estateExpenseBillDetail.setElectricStartNum(0);
                                        estateExpenseBillDetail.setElectricEndNum(0);
                                        estateExpenseBillDetail.setElectricUsage(0.0);
                                        estateExpenseBillDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 3:
                                        estateExpenseBillDetail.setPropertyFee(save.getCost());
                                        break;
                                    case 4:
                                        estateExpenseBillDetail.setBroadBandCharges(save.getCost());
                                        break;
                                    case 5:
                                        estateExpenseBillDetail.setTvFee(save.getCost());
                                        break;
                                    case 6:
                                        estateExpenseBillDetail.setGasStartNum(0);
                                        estateExpenseBillDetail.setGasEndNum(0);
                                        estateExpenseBillDetail.setGasUsage(0.0);
                                        estateExpenseBillDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 7:
                                        estateExpenseBillDetail.setHeatingBill(save.getCost());
                                        break;
                                }

                                estateExpenseBillDetailRepository.save(estateExpenseBillDetail);

                            }
                        }

                    }else{
                        //当前时间不在时间周期内的账单
                        //整个周期账单小于当前时间
                        if(currentDate.getTime() > startDate.getTime() &&  currentDate.getTime() > endDate.getTime()){
                            //规则生成时间 == 当前时间 ，即规则建立当天就补全当前房屋当前类型的未生成账单的周期时间段数据
                            String curr = df.format(currentDate);
                            if(curr.equals(createTime)){
                                //拆分时间段
                                List<Map<String,String>> dateList = new ArrayList<>();
                                Date tempDate = startDate;
                                BigDecimal month = new BigDecimal(1);
                                switch(chargeMode){
                                    case 1:
                                        dateList = dateList(tempDate , endDate ,1);
                                        month = new BigDecimal(1);
                                        break;
                                    case 2:
                                        dateList = dateList(tempDate , endDate ,3);
                                        month = new BigDecimal(3);
                                        break;
                                    case 3:
                                        dateList = dateList(tempDate , endDate ,6);
                                        month = new BigDecimal(6);
                                        break;
                                    case 4:
                                        dateList = dateList(tempDate , endDate ,12);
                                        month = new BigDecimal(12);
                                        break;
                                }

                                for (Map<String, String> m : dateList) {
                                    //按对应方式生成账单
                                    String start = m.get("start");
                                    String end = m.get("end");

                                    //获取截止时间
                                    Date startTimes = df.parse(start);

                                    if(dateFlagObj != null){
                                        Integer dateFlag = (Integer) dateFlagObj; //时间标志：1开始时间 2结束时间
                                        if(dateFlag.equals(2)){
                                            startTimes = df.parse(end);
                                        }
                                    }

                                    Date closeTime = null;
                                    if (flag.equals(1)) {  // 1前 2后
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, -day);
                                        closeTime = c.getTime();
                                    } else {
                                        Calendar c = Calendar.getInstance();
                                        c.setTime(startTimes);
                                        c.add(Calendar.DAY_OF_MONTH, day);
                                        closeTime = c.getTime();
                                    }


                                    //int dayNum = DateUtils.daysBetween(df.parse(start),df.parse(end));
                                    //价格:单位分
                                    Integer cose = 0;
                                    BigDecimal price = new BigDecimal(other.getPrice());
                                    //计量单位，如：月/度/平方
                                    String unit = other.getUnit();
                                    BigDecimal temp = null;
                                    switch ((Integer) rMap.get("chargeType")){  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 3:
                                            //物业费 = 面积 * 单价 * 天数
                                            BigDecimal area = house.getArea();
                                            temp = area.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 4:
                                            //宽带费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 5:
                                            //电视费 = 月份 * 单价
                                            temp = month.multiply(price);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                        case 7:
                                            //暖气费 = 面积 * 单价 * 日期
                                            BigDecimal area1 = house.getArea();
                                            temp = area1.multiply(price).multiply(month);
                                            cose = Integer.valueOf(temp.setScale(0,BigDecimal.ROUND_HALF_UP).toString());
                                            break;
                                    }

                                    List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                                    String matchUserId = null;
                                    if (communityHouseUserList.size() > 0) {
                                        matchUserId = communityHouseUserList.get(0).getUserId();
                                    }

                                    if(houseNature != null && houseNature.equals(1)){  // 公租房
                                        List<String> hlist = new ArrayList<>();
                                        hlist.add(houseId);
                                        List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist,1);
                                        if(hmUserList.size() > 0){
                                            matchUserId = hmUserList.get(0).getMatchUserId();
                                        }
                                    }

                                    //生成账单
                                    EstateExpenseBill estateExpenseBill = new EstateExpenseBill();

                                    estateExpenseBill.setHouseId(houseId);
                                    estateExpenseBill.setChargeType(chargeType);
                                    estateExpenseBill.setCommunityId(house.getResidenceCommunityId());
                                    estateExpenseBill.setBuildingNum(house.getBuildingNum());
                                    estateExpenseBill.setUnit(house.getUnit());
                                    estateExpenseBill.setOrgId(house.getHousePropertyId());
                                    estateExpenseBill.setPaymentStatus(0);
                                    estateExpenseBill.setRoomNumber(house.getRoomNumber());
                                    estateExpenseBill.setMatchUserId(matchUserId);
                                    estateExpenseBill.setCost(cose);
                                    estateExpenseBill.setMeasureUnit(unit);
                                    estateExpenseBill.setStartTime(df.parse(start));
                                    estateExpenseBill.setEndTime(df.parse(end));
                                    estateExpenseBill.setCreateTime(currentDate);
                                    estateExpenseBill.setAuditStatus(0);      //'审核状态：0未审核 1已审核'
                                    estateExpenseBill.setBillType(1);
                                    estateExpenseBill.setShouldPayTime(closeTime);
                                    estateExpenseBill.setRuleId(rid);

                                    EstateExpenseBill save = estateExpenseBillRepository.save(estateExpenseBill);

                                    EstateExpenseBillDetail estateExpenseBillDetail = new EstateExpenseBillDetail();
                                    estateExpenseBillDetail.setExpenseBillId(save.getId());
                                    estateExpenseBillDetail.setChargeType(save.getChargeType());
                                    switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                        case 1:
                                            estateExpenseBillDetail.setWaterStartNum(0);
                                            estateExpenseBillDetail.setWaterEndNum(0);
                                            estateExpenseBillDetail.setWaterUsage(0.0);
                                            estateExpenseBillDetail.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                            break;
                                        case 2:
                                            estateExpenseBillDetail.setElectricStartNum(0);
                                            estateExpenseBillDetail.setElectricEndNum(0);
                                            estateExpenseBillDetail.setElectricUsage(0.0);
                                            estateExpenseBillDetail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 3:
                                            estateExpenseBillDetail.setPropertyFee(save.getCost());
                                            break;
                                        case 4:
                                            estateExpenseBillDetail.setBroadBandCharges(save.getCost());
                                            break;
                                        case 5:
                                            estateExpenseBillDetail.setTvFee(save.getCost());
                                            break;
                                        case 6:
                                            estateExpenseBillDetail.setGasStartNum(0);
                                            estateExpenseBillDetail.setGasEndNum(0);
                                            estateExpenseBillDetail.setGasUsage(0.0);
                                            estateExpenseBillDetail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                            break;
                                        case 7:
                                            estateExpenseBillDetail.setHeatingBill(save.getCost());
                                            break;
                                    }

                                    estateExpenseBillDetailRepository.save(estateExpenseBillDetail);

                                }

                            }

                        }

                    }

                }

            }

            log.info(" 生成其它费用账单明细   end");

        }catch (Exception e){
            log.error("生成其它费用账单明细异常  " + e.getMessage(), e);
        }
    }


    public List<Map<String,String>> dateList(Date tempDate ,Date endDate,int month){

        List<Map<String,String>> dateList = new ArrayList<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Calendar startCal = Calendar.getInstance();
        Calendar endCal = Calendar.getInstance();

        for(;;){
            Map<String,String> map =new HashMap<>();
            startCal.setTime(tempDate);
            String start = df.format(startCal.getTime());
            map.put("start",start);
            startCal.add(Calendar.MONTH, month);//下一个开始日期

            endCal.setTime(startCal.getTime());
            endCal.add(Calendar.DAY_OF_MONTH, -1);
            Date temEnd = endCal.getTime();
            //拆分后的结束时间 > 周期结束时间
            if(temEnd.getTime() >= endDate.getTime()){
                map.put("end",df.format(endDate));
                dateList.add(map);
                break;
            }else{
                tempDate = startCal.getTime();
                map.put("end",df.format(temEnd));
                dateList.add(map);
            }
        }

        return dateList;
    }


}
